/**
 * Copyright (c) 2015-2016, Chill Zhuang 庄骞 (smallchill@163.com).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.ml.mall.utils;

import com.alibaba.fastjson.JSON;
import com.ml.mall.bean.base.ApiRestResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.*;
import java.util.*;

/**
 * @description: TODO
 * @author kyyang
 * @date 2020/12/28 20:26
 * @version 1.0
 */
@Slf4j
public class HttpUtil {

    public static String getIp() {
        return HttpUtil.getRequest().getRemoteHost();
    }

    /**
     * 获取所有请求的值
     */
    public static Map<String, String> getRequestParameters() {
        HashMap<String, String> values = new HashMap<>(20);
        HttpServletRequest request = HttpUtil.getRequest();
        Enumeration enums = request.getParameterNames();
        while (enums.hasMoreElements()) {
            String paramName = (String) enums.nextElement();
            String paramValue = request.getParameter(paramName);
            values.put(paramName, paramValue);
        }
        return values;
    }

    /**
     * 获取 HttpServletRequest
     */
    public static HttpServletResponse getResponse() {
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        return response;
    }

    /**
     * 获取 包装防Xss Sql注入的 HttpServletRequest
     *
     * @return request
     */
    public static HttpServletRequest getRequest() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        return new WafRequestWrapper(request);
    }

    public static String getToken() {
        return getRequest().getHeader("Authorization");
    }


    /**
     * POST
     * @param
     * @param
     * @return
     * @throws IOException
     */
    public static String doPostJson(String urlstr, Map<String,Object> map) throws IOException {
        DataOutputStream out = null;
        HttpURLConnection connection = null;
        BufferedReader reader = null;
        StringBuffer sb = new StringBuffer("");
        try {
            URL url = new URL(urlstr);
            connection = (HttpURLConnection) url.openConnection();
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setRequestMethod("POST");
            connection.setUseCaches(false);
            connection.setInstanceFollowRedirects(true);
            connection.setRequestProperty("Content-Type", "application/json");
            connection.setConnectTimeout(5000);
            connection.connect();
            out = new DataOutputStream(connection.getOutputStream());
//            json与fromde区别就在于out.write的数据形式 daizh
            out.write(JSON.toJSONString(map).getBytes("UTF-8"));
            out.flush();
            //读取响应
            reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            String lines;

            while ((lines = reader.readLine()) != null) {
                lines = new String(lines.getBytes(), "utf-8");
                sb.append(lines);
            }
            log.info("doPostJson======responce:"+sb.toString());
            reader.close();

        }catch (Exception e){
            log.error("Exception:[{}]",e);
        }finally {
            if(out!=null){
                out.close();
            }
            if(connection!=null){
                connection.disconnect();
            }
            if(reader!=null){
                reader.close();
            }
            return sb.toString();
        }

    }


    /**
     * @description: TODO
     * @author kyyang
     * @date 2021/1/26 18:41
     * @version 1.0
     */
    public String doGetToString(String url) throws IOException {
        HttpGet httpGet = new HttpGet(url);
        //httpGet.setConfig(requestConfig);
        CloseableHttpResponse response = null;

        try {
            response = HttpClientBuilder.create().build().execute(httpGet);
            if (response.getStatusLine().getStatusCode() == 200) {
                // 响应成功，返回数据
                return EntityUtils.toString(response.getEntity(), "UTF-8");
            }
        } finally {
            // 关闭请求，释放资源
            if (response != null) {
                response.close();
            }
        }
        return null;
    }

    /**
     * @description: TODO
     * @author kyyang
     * @date 2021/1/26 18:41
     * @version 1.0
     */
    public static String httpGet(String url) {

        String result = "";
        BufferedReader in = null;
        try {
            String urlNameString = url;
            URL realUrl = new URL(urlNameString);
            // 打开和URL之间的连接
            URLConnection connection = realUrl.openConnection();
            // 设置通用的请求属性
            connection.setRequestProperty("accept", "*/*");
            connection.setRequestProperty("connection", "Keep-Alive");
            connection.setRequestProperty("user-agent",
                    "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            // 建立实际的连接
            connection.connect();
            // 获取所有响应头字段
            Map<String, List<String>> map = connection.getHeaderFields();
            // 遍历所有的响应头字段
            for (String key : map.keySet()) {
                System.out.println(key + "--->" + map.get(key));
            }
            // 定义 BufferedReader输入流来读取URL的响应
            in = new BufferedReader(new InputStreamReader(
                    connection.getInputStream()));
            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            System.out.println("发送GET请求出现异常！" + e);
            e.printStackTrace();
        }
        // 使用finally块来关闭输入流
        finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
        return result;
    }

    /**
     * @description: TODO
     * @author kyyang
     * @date 2021/1/26 18:41
     * @version 1.0
     */
    public ApiRestResult doGet(String url) throws
            IOException {
        // 创建http GET请求
        HttpGet httpGet = new HttpGet(url);
        //	httpGet.setConfig(this.requestConfig);
        CloseableHttpResponse response = null;
        try {
            // 执行请求
            response = HttpClientBuilder.create().build().execute(httpGet);
            int statusCode = response.getStatusLine().getStatusCode();
            String body = "";
            if (response.getEntity() != null) {
                body = EntityUtils.toString(response.getEntity(),
                        "UTF-8");
            }
            return  ApiRestResult.err(statusCode+"",body);
        } finally {
            if (response != null) {
                response.close();
            }
        }
    }

    /**
     * @description: TODO
     * @author kyyang
     * @date 2021/1/27 22:54
     * @version 1.0
     */
    public ApiRestResult doGet(String url, Map<String, Object> param)
            throws IOException, URISyntaxException {
        // 定义请求的参数
        URIBuilder uriBuilder = new URIBuilder(url);
        for (Map.Entry<String, Object> entry : param.entrySet()) {
            uriBuilder
                    .addParameter(entry.getKey(), entry.getValue().toString());
        }
        return doGet(uriBuilder.build().toString());
    }

    /**
     *
     * @param httpUrl  请求的url
     * @param param  form表单的参数（key,value形式）
     * @return
     */
    public static String doPostForm(String httpUrl, Map<String,String> param) {

        HttpURLConnection connection = null;
        InputStream is = null;
        OutputStream os = null;
        BufferedReader br = null;
        String result = null;
        try {
            URL url = new URL(httpUrl);
            // 通过远程url连接对象打开连接
            connection = (HttpURLConnection) url.openConnection();
            // 设置连接请求方式
            connection.setRequestMethod("POST");
            // 设置连接主机服务器超时时间：15000毫秒
            connection.setConnectTimeout(15000);
            // 设置读取主机服务器返回数据超时时间：60000毫秒
            connection.setReadTimeout(60000);

            // 默认值为：false，当向远程服务器传送数据/写数据时，需要设置为true
            connection.setDoOutput(true);
            // 默认值为：true，当前向远程服务读取数据时，设置为true，该参数可有可无
            connection.setDoInput(true);
            // 设置传入参数的格式:请求参数应该是 name1=value1&name2=value2 的形式。
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            // 设置鉴权信息：Authorization: Bearer da3efcbf-0845-4fe3-8aba-ee040be542c0
            //connection.setRequestProperty("Authorization", "Bearer da3efcbf-0845-4fe3-8aba-ee040be542c0");
            // 通过连接对象获取一个输出流
            os = connection.getOutputStream();
            // 通过输出流对象将参数写出去/传输出去,它是通过字节数组写出的(form表单形式的参数实质也是key,value值的拼接，类似于get请求参数的拼接)
            os.write(createLinkString(param).getBytes());
            // 通过连接对象获取一个输入流，向远程读取
            if (connection.getResponseCode() == 200) {

                is = connection.getInputStream();
                // 对输入流对象进行包装:charset根据工作项目组的要求来设置
                br = new BufferedReader(new InputStreamReader(is, "UTF-8"));

                StringBuffer sbf = new StringBuffer();
                String temp = null;
                // 循环遍历一行一行读取数据
                while ((temp = br.readLine()) != null) {
                    sbf.append(temp);
                    sbf.append("\r\n");
                }
                result = sbf.toString();
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            if (null != br) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != os) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            // 断开与远程地址url的连接
            connection.disconnect();
        }
        return result;
    }

    /**
     * 把数组所有元素排序，并按照“参数=参数值”的模式用“&”字符拼接成字符串
     * @param params 需要排序并参与字符拼接的参数组
     * @return 拼接后字符串
     */
    public static String createLinkString(Map<String, String> params) {

        List<String> keys = new ArrayList<String>(params.keySet());
        Collections.sort(keys);

        StringBuilder prestr = new StringBuilder();
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = params.get(key);
//            String value = JSON.toJSONString(params.get(key)); //可以接其他形式直接转String;点卡的json会多格式化一次不能使用
            if (i == keys.size() - 1) {// 拼接时，不包括最后一个&字符
                prestr.append(key).append("=").append(value);
            } else {
                prestr.append(key).append("=").append(value).append("&");
            }
        }

        return prestr.toString();
    }


    //发送Https 的请求
    //http的三种情况 //dzh 1：机构颁发的证书；直接请求 跟http一样；2：个人证书；需要获取证书并当如到keystore
    // 第三种 要求携带证书的 需要使用必须使用HttpsURLConnection方式 从网站开发者出获取生成证书的密钥库cacert.keystore 需要单独方法 ：参见https://blog.csdn.net/shumeng_xiaoyan/article/details/76503601
}
